package com.jgy.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.jgy.mapper.DpTemplateMapper;
import com.jgy.pojo.vo.DpFieldInfo;
import com.jgy.pojo.vo.DpTemplateInfo;
import com.jgy.pojo.vo.DpTemplatePageInfo;
import com.jgy.pojo.vo.DpTemplateParameter;
import com.jgy.utils.DpTemplateInfoUtil;
import com.jgy.utils.DpViewType;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @author 姜光远
 * @date 2022/8/17 16:10
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DpTemplateService {

    private final DpTemplateMapper dpTemplateMapper;

//    private final DpAssessmentComputingService dpAssessmentComputingService;

//    private final DpTemplateEChartService dpTemplateEChartService;

//    private final Map<String, DpTemplateCallService> dpTemplateCallServiceMap;

    /**
     * 视图数据查询接口
     *
     * @param viewKey             视图id
     * @param dpTemplateParameter 前端传递参数
     * @return DpTemplatePageInfo
     */
    public DpTemplatePageInfo<Map<String, Object>> call(String viewKey, DpTemplateParameter dpTemplateParameter) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        DpTemplatePageInfo<Map<String, Object>> dpTemplatePageInfo = new DpTemplatePageInfo<>();
        DpTemplateInfo dpTemplateInfo = DpTemplateInfoUtil.get(viewKey);
        if (dpTemplateInfo == null || dpTemplateInfo.getViewConfig() == null) {
            log.error("视图：{}，未找到对应配置", viewKey);
            return dpTemplatePageInfo;
        }
        if (CollectionUtil.isEmpty(dpTemplateInfo.getViewConfig().getColumnList())) {
            List<DpFieldInfo> list = dpTemplateMapper.getColumnList(dpTemplateInfo.getViewConfig().getDbId());
            if (CollectionUtil.isEmpty(list)) {
                return dpTemplatePageInfo;
            }
            dpTemplateInfo.getViewConfig().setColumnList(list);
        }
        if (dpTemplateInfo.getViewConfig().getDpViewType().equals(DpViewType.SQL)) {
            log.info("视图：{}，执行SQL方式", viewKey);
            dpTemplatePageInfo = callSql(dpTemplateInfo, dpTemplateParameter);
        }
//        else if (dpTemplateInfo.getViewConfig().getDpViewType().equals(DpViewType.BEAN)) {
//            log.info("视图：{}，执行BEAN方式", viewKey);
//            if (dpTemplateCallServiceMap.containsKey(dpTemplateInfo.getViewKey())) {
//                dpTemplatePageInfo = dpTemplateCallServiceMap.get(dpTemplateInfo.getViewKey())
//                        .processData(dpTemplateInfo, dpTemplateParameter);
//            }
//        }
        dpTemplatePageInfo.setColumnList(dpTemplateInfo.getViewConfig().getColumnList());
        return dpTemplatePageInfo;
    }

    /**
     * 视图数据查询sql接口
     *
     * @param dpTemplateInfo      视图信息
     * @param dpTemplateParameter 前端传递参数
     * @return DpTemplatePageInfo
     */
    private DpTemplatePageInfo<Map<String, Object>> callSql(DpTemplateInfo dpTemplateInfo,
                                                            DpTemplateParameter dpTemplateParameter) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        if (StringUtils.isNotBlank(dpTemplateInfo.getViewConfig().getTableInfo())) {
            return callCommonSq1l(dpTemplateInfo, dpTemplateParameter);
        } else {
            return callOwnSql(dpTemplateInfo, dpTemplateParameter, false);
        }
    }

    /**
     * 视图数据查询SQL，通用查询接口
     *
     * @param dpTemplateInfo      视图信息
     * @param dpTemplateParameter 前端传递参数
     * @return DpTemplatePageInfo
     */
    private DpTemplatePageInfo<Map<String, Object>> callCommonSq1l(DpTemplateInfo dpTemplateInfo,
                                                                   DpTemplateParameter dpTemplateParameter) {
        log.info(dpTemplateInfo.getViewKey());
        StringBuilder stringBuilder = new StringBuilder(" select ");
        dpTemplateInfo.getViewConfig().getColumnList().forEach(fieldInfo -> stringBuilder
                .append(fieldInfo.getField()).append(","));
        PageHelper.startPage(dpTemplateParameter.getPageNum(), dpTemplateParameter.getPageSize());
        stringBuilder.setLength(stringBuilder.length() - 1);
        stringBuilder.append(" from ").append(dpTemplateInfo.getViewConfig().getTableInfo());
        List<Map<String, Object>> list = dpTemplateMapper.query(stringBuilder.toString(),
                dpTemplateParameter.getParams(),dpTemplateInfo.getViewConfig().getDbId());
        return new DpTemplatePageInfo<>(list);
    }

    /**
     * 视图数据查询SQL，mybatis查询接口
     *
     * @param dpTemplateInfo      视图信息
     * @param dpTemplateParameter 前端传递参数
     * @param chart               是否图标查询 true or false
     * @return DpTemplatePageInfo
     */
    private DpTemplatePageInfo<Map<String, Object>> callOwnSql(DpTemplateInfo dpTemplateInfo,
                                                               DpTemplateParameter dpTemplateParameter,
                                                               boolean chart) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//        try {
            String method = dpTemplateInfo.getViewKey();
            if (chart) {
                method = dpTemplateInfo.getViewKey() + "Chart";
            } else {
                PageHelper.startPage(dpTemplateParameter.getPageNum(), dpTemplateParameter.getPageSize());
            }
            Object mapperCallBean = DpTemplateInfoUtil.getMapper(dpTemplateInfo.getViewKey());
            Method loginMethod = mapperCallBean.getClass().getMethod(method, Map.class);
            Object object = loginMethod.invoke(mapperCallBean, dpTemplateParameter.getParams());
            return new DpTemplatePageInfo<>((List<Map<String, Object>>) object);
//        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
//            log.error(e.getMessage(), e);
//            log.error("调用视图：{} 解析失败！", dpTemplateInfo.getViewKey());
//        }
//        return new DpTemplatePageInfo<>();
    }

    /**
     * 视图图标查询接口
     *
     * @param viewKey             视图id
     * @param dpTemplateParameter 前端传递参数
     * @return JSONObject
     */
//    public JSONObject callCharts(String viewKey, DpTemplateParameter dpTemplateParameter) {
//        JSONObject jsonObject = new JSONObject();
//        DpTemplateInfo dpTemplateInfo = DpTemplateInfoUtil.get(viewKey);
//        if (dpTemplateInfo == null || dpTemplateInfo.getChartConfig() == null) {
//            log.error("图表：{}，未找到对应配置", viewKey);
//            return jsonObject;
//        }
//        if (dpTemplateInfo.getChartConfig().getChartType().equals(DpViewType.SQL)) {
//            log.info("图表：{}，执行SQL方式", viewKey);
//            DpTemplatePageInfo<Map<String, Object>> pageInfo = callOwnSql(dpTemplateInfo,
//                    dpTemplateParameter, true);
//            jsonObject = dpTemplateEChartService.initBarChart(pageInfo.getList());
//        } else if (dpTemplateInfo.getChartConfig().getChartType().equals(DpViewType.BEAN)) {
//            log.info("图表：{}，执行BEAN方式", viewKey);
//            if (dpTemplateCallServiceMap.containsKey(dpTemplateInfo.getViewKey())) {
//                jsonObject = dpTemplateCallServiceMap.get(dpTemplateInfo.getViewKey())
//                        .process(dpTemplateInfo, dpTemplateParameter);
//
//            }
//        }
//        return jsonObject;
//    }

    /**
     * 树节点调用查询
     *
     * @param viewKey 视图id
     * @return R
     */
//    public R<List<TreeVo>> callTree(String viewKey) {
//        DpTemplateInfo dpTemplateInfo = DpTemplateInfoUtil.get(viewKey);
//        if (dpTemplateInfo == null || dpTemplateInfo.getTreeConfig() == null) {
//            log.error("视图：{}，未找到对应配置", viewKey);
//            return R.failed("未找到对应配置");
//        }
//        return dpAssessmentComputingService.getTreeList(dpTemplateInfo.getTreeConfig().getTreeFilterType(),
//                dpTemplateInfo.getTreeConfig().getTreeType());
//    }

    /**
     * 调用视图对应的配置详细
     *
     * @param viewKey 视图id
     * @return jsonObject
     */
    public JSONObject callConfig(String viewKey) {
        DpTemplateInfo dpTemplateInfo = DpTemplateInfoUtil.get(viewKey);
        if (dpTemplateInfo == null) {
            log.error("视图：{}，未找到对应配置", viewKey);
            return new JSONObject().fluentPut("msg", "未找到对应配置").fluentPut("success", false);
        }
        return new JSONObject()
                .fluentPut("hideChart", dpTemplateInfo.getChartConfig() == null)
                .fluentPut("hideTree", dpTemplateInfo.getTreeConfig() == null)
                .fluentPut("hideTable", dpTemplateInfo.getViewConfig() == null)
                .fluentPut("conditionConfig", dpTemplateInfo.getConditionConfig())
                .fluentPut("showCheckBox", dpTemplateInfo.getTreeConfig() != null &&
                        dpTemplateInfo.getTreeConfig().isShowCheckBox());
    }

    /**
     * 模板查询初始化
     */
    public void init() {
        log.info("初始化模板。。。。。。。。。");
        List<Resource> list = new ArrayList<>();
        try {
            //扫描配置文件 并加入到全局变量中
            ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resourceResolver.getResources("classpath*:/template/**/*_view.json");
            //Resource[] resources1 = resourceResolver.getResources("classpath*:/config/**/*_view.json");
            if (resources.length > 0) {
                list.addAll(Arrays.asList(resources));
            }
            if (list.size() > 0) {
                List<Resource> resourceList = clearDupList(list.toArray(new Resource[0]));
                File f = new File(System.getProperty("user.dir") + File.separator + "template");
                for (Resource resource : resourceList) {
                    FileUtils.copyInputStreamToFile(resource.getInputStream(), f);
                    cn.hutool.json.JSONArray jsonArray = JSONUtil.readJSONArray(f, StandardCharsets.UTF_8);
                    for (int i = 0; i < jsonArray.size(); i++) {
                        DpTemplateInfo dpTemplateInfo = JSONUtil.toBean(jsonArray.getJSONObject(i),
                                DpTemplateInfo.class);
                        if (validate(dpTemplateInfo)) {
                            DpTemplateInfoUtil.put(dpTemplateInfo);
                            DpTemplateInfoUtil.addMapper(dpTemplateInfo.getViewKey(), dpTemplateInfo.getClassPath());
                        }
                    }
                }
                FileUtils.deleteQuietly(f);
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 清除重复的view，优先保留jar包外的
     *
     * @param resources 视图列表
     * @return 处理后的视图列表
     */
    private List<Resource> clearDupList(Resource[] resources) {
        List<Resource> list = new ArrayList<>();
        Map<String, String> calledMap = new HashMap<>();
        for (int i = 0; i < resources.length; i++) {
            if (list.contains(resources[i])) {
                continue;
            }
            for (int j = i + 1; j < resources.length; j++) {
                if (Objects.equals(resources[i].getFilename(), resources[j].getFilename())) {
                    Resource resource;
                    try {
                        resource = resources[j].getURI().getScheme().equals("jar") ? resources[i] : resources[j];
                        if (!calledMap.containsKey(resource.getFilename())) {
                            list.add(resource);
                            calledMap.put(resource.getFilename(), resource.getFilename());
                        }
                    } catch (IOException e) {
                        log.error(e.getMessage(), e);
                    }
                    break;
                }
            }
            if (!calledMap.containsKey(resources[i].getFilename())) {
                list.add(resources[i]);
                calledMap.put(resources[i].getFilename(), resources[i].getFilename());
            }
        }
        return list;
    }

    private boolean validate(DpTemplateInfo dpTemplateInfo) {
        boolean isContinue = true;
        if (StringUtils.isEmpty(dpTemplateInfo.getViewKey())) {
            log.error("视图：{}，viewKey未配置。", dpTemplateInfo.getViewKey());
            isContinue = false;
        }
        if (dpTemplateInfo.getViewConfig() != null) {
            if (dpTemplateInfo.getViewConfig().getDpViewType() == null ||
                    StringUtils.isEmpty(dpTemplateInfo.getViewConfig().getDpViewType().getValue())) {
                log.error("视图：{}，viewType未配置", dpTemplateInfo.getViewKey());
                isContinue = false;
            }
            /*if (dpTemplateInfo.getViewConfig().getColumnList() == null) {
                log.error("视图：{}，视图列未配置。", dpTemplateInfo.getViewKey());
                isContinue = false;
            }*/
        }
        /*if (StringUtils.isEmpty(templateInfo.getTableInfo())) {
            log.error("视图：{}，视图查询sql未配置。", templateInfo.getViewKey());
            isContinue = false;
        }*/
        return isContinue;
    }
}
